/**
 ******************************************************************************
 * @file    system_hk32f030m.c
 * @author  laura.C
 * @version V1.0
 * @brief   API file of system clk config
 * @changelist
 ******************************************************************************
 */

/*
This file configures the system clock as follows:
 *=============================================================================
 *                         Supported hk32f030m device
 *-----------------------------------------------------------------------------
 *        System Clock source                    | HSI32M
 *-----------------------------------------------------------------------------
 *        SYSCLK(Hz)                             | 32000000
 *-----------------------------------------------------------------------------
 *        HCLK(Hz)                               | 32000000
 *-----------------------------------------------------------------------------
 *        AHB Prescaler                          | 1
 *-----------------------------------------------------------------------------
 *        APB1 Prescaler                         | 1
 *-----------------------------------------------------------------------------
 *=============================================================================
 ******************************************************************************

 */
#include "hk32f030m.h"
/*system clock source*/

#define SYSCLK_SRC_HSI8M     0x2
#define SYSCLK_SRC_HSI16M    0x3
#define SYSCLK_SRC_HSI32M    0x4
#define SYSCLK_SRC_LSI       0x5
#define SYSCLK_SCR_EXTCLK_IO 0x6

#define SYSCLK_SOURCE SYSCLK_SRC_HSI32M

// #define VECT_TAB_SRAM
#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */


#if (SYSCLK_SOURCE == SYSCLK_SRC_HSI8M)
#define SYSCLK_FREQ_HSI_8M 8000000
uint32_t SystemCoreClock = SYSCLK_FREQ_HSI_8M; /*!< System Clock Frequency (Core Clock) */
static void SetSysClockToHSI_8M(void);
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI16M)
#define SYSCLK_FREQ_HSI_16M 16000000
uint32_t SystemCoreClock = SYSCLK_FREQ_HSI_16M; /*!< System Clock Frequency (Core Clock) */
static void SetSysClockToHSI_16M(void);
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI32M)
#define SYSCLK_FREQ_HSI_32M HSI_VALUE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSI_32M; /*!< System Clock Frequency (Core Clock) */
static void SetSysClockToHSI_32M(void);
#elif (SYSCLK_SOURCE == SYSCLK_SRC_LSI)
#define SYSCLK_FREQ_LSI LSI_VALUE
uint32_t SystemCoreClock = SYSCLK_FREQ_LSI; /*!< System Clock Frequency (Core Clock) */
static void SetSysClockToLSI(void);
#elif (SYSCLK_SOURCE == SYSCLK_SCR_EXTCLK_IO)
#define SYSCLK_FREQ_EXTCLK EXTCLK_VALUE
uint32_t SystemCoreClock = SYSCLK_FREQ_EXTCLK; /*!< System Clock Frequency (Core Clock) */
static void SetSysClockToEXTCLK(void);
#endif

static void SetSysClock(void);

/**
 * @brief  Setup the microcontroller system.
 *         Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
 * @param  None
 * @retval None
 */
void SystemInit(void) {
    /* Set HSION bit */
    RCC->CR |= (uint32_t)0x00000001;

    /* Reset SW[1:0], HPRE[3:0], PPRE[2:0] and MCOSEL[2:0] bits */
    RCC->CFGR &= (uint32_t)0xF8FFB81C;

    /* Reset USARTSW[1:0], I2CSW bits */
    RCC->CFGR3 &= (uint32_t)0xFFFFFFEC;

    /* Disable all interrupts */
    RCC->CIR = 0x00000000;

    SetSysClock();

#ifdef VECT_TAB_SRAM
    SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE; /* Vector Table Relocation in Internal SRAM. */
#else
    FLASH->INT_VEC_OFFSET = VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}


/**
 * @brief  Configures the System clock frequency, HCLK, PCLK prescalers.
 * @param  None
 * @retval None
 */
static void SetSysClock(void) {
    /*reload the  hsi trimming value to the bit3~bit13  of RCC_CR register */
    uint32_t u32HSIFLASH = 0;
    uint32_t u32RCC_CR = 0;
    uint32_t u32HSITemp = 0;
    uint16_t u16HSITempH = 0;
    uint16_t u16HSITempL = 0;

    u32HSIFLASH = *(uint32_t *)0x1FFFF820;
    u16HSITempH = (uint16_t)(u32HSIFLASH >> 16);
    u16HSITempL = (uint16_t)(u32HSIFLASH);

    if (!(u16HSITempH & u16HSITempL)) {
        u32HSITemp = RCC->CR;
        u32HSITemp &= (uint32_t)((uint32_t) ~(RCC_CR_HSITRIM | RCC_CR_HSICAL));
        u32RCC_CR = (uint32_t)(((u16HSITempL & 0x001F) << 3) | (((u16HSITempL >> 5) & 0x003F) << 8));
        RCC->CR |= u32RCC_CR;
    }
    /*end*/
#if (SYSCLK_SOURCE == SYSCLK_SRC_HSI8M)
    SetSysClockToHSI_8M();
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI16M)
    SetSysClockToHSI_16M();
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI32M)
    SetSysClockToHSI_32M();
#elif (SYSCLK_SOURCE == SYSCLK_SRC_LSI)
    SetSysClockToLSI();
#elif (SYSCLK_SOURCE == SYSCLK_SCR_EXTCLK_IO)
    SetSysClockToEXTCLK();
#endif

    /* If none of the define above is enabled, the HSI is used as System clock  source (default after reset) */
}

#if (SYSCLK_SOURCE == SYSCLK_SRC_HSI8M)
static void SetSysClockToHSI_8M(void) {
    __IO uint32_t StartUpCounter = 0, HSIStatus = 0;
    __IO uint32_t ACRreg = 0;
    __IO uint32_t RCCHCLKReg = 0;
    __IO uint32_t RCCPCLKReg = 0;
    /* Enable HSI */
    RCC->CR |= RCC_CR_HSION;

    RCC->CFGR4 &= ~RCC_RCC_CFGR4_FLITFCLK_PRE;
    RCC->CFGR4 |= (((uint32_t)0x07) << RCC_RCC_CFGR4_FLITFCLK_PRE_Pos);

    /* Wait till HSI is ready and if Time out is reached exit */
    do {
        HSIStatus = RCC->CR & RCC_CR_HSIRDY;
        StartUpCounter++;
    } while ((HSIStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));

    if ((RCC->CR & RCC_CR_HSIRDY) != RESET) {
        HSIStatus = (uint32_t)0x01;
    }
    else {
        HSIStatus = (uint32_t)0x00;
    }

    if (HSIStatus == (uint32_t)0x01) {
        /* Flash wait state */
        ACRreg = FLASH->ACR;
        ACRreg &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
        FLASH->ACR = (uint32_t)(FLASH_Latency_0 | ACRreg);

        RCCHCLKReg = RCC->CFGR;
        RCCHCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_HPRE_Msk);
        /* HCLK = SYSCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_HPRE_DIV4 | RCCHCLKReg);

        RCCPCLKReg = RCC->CFGR;
        RCCPCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_PPRE_Msk);
        /* PCLK = HCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_PPRE_DIV1 | RCCPCLKReg);

        /* Select HSI as system clock source */
        RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI;

        /* Wait till HSI is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
        }
    }
    else { /* If fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */
    }
}
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI16M)
static void SetSysClockToHSI_16M(void) {
    __IO uint32_t StartUpCounter = 0, HSIStatus = 0;
    __IO uint32_t ACRreg = 0;
    __IO uint32_t RCCHCLKReg = 0;
    __IO uint32_t RCCPCLKReg = 0;
    /* Enable HSI */
    RCC->CR |= RCC_CR_HSION;

    RCC->CFGR4 &= ~RCC_RCC_CFGR4_FLITFCLK_PRE;
    RCC->CFGR4 |= (((uint32_t)0x07) << RCC_RCC_CFGR4_FLITFCLK_PRE_Pos);
    /* Wait till HSI is ready and if Time out is reached exit */
    do {
        HSIStatus = RCC->CR & RCC_CR_HSIRDY;
        StartUpCounter++;
    } while ((HSIStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));

    if ((RCC->CR & RCC_CR_HSIRDY) != RESET) {
        HSIStatus = (uint32_t)0x01;
    }
    else {
        HSIStatus = (uint32_t)0x00;
    }

    if (HSIStatus == (uint32_t)0x01) {
        /* Flash wait state */
        ACRreg = FLASH->ACR;
        ACRreg &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
        FLASH->ACR = (uint32_t)(FLASH_Latency_1 | ACRreg);

        RCCHCLKReg = RCC->CFGR;
        RCCHCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_HPRE_Msk);
        /* HCLK = SYSCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_HPRE_DIV2 | RCCHCLKReg);

        RCCPCLKReg = RCC->CFGR;
        RCCPCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_PPRE_Msk);
        /* PCLK = HCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_PPRE_DIV1 | RCCPCLKReg);

        /* Select HSI as system clock source */
        RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI;

        /* Wait till HSI is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
        }
    }
    else { /* If fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */
    }
}
#elif (SYSCLK_SOURCE == SYSCLK_SRC_HSI32M)
static void SetSysClockToHSI_32M(void) {
    __IO uint32_t StartUpCounter = 0, HSIStatus = 0;
    __IO uint32_t ACRreg = 0;
    __IO uint32_t RCCHCLKReg = 0;
    __IO uint32_t RCCPCLKReg = 0;
    /* Enable HSI */
    RCC->CR |= RCC_CR_HSION;

    RCC->CFGR4 &= ~RCC_RCC_CFGR4_FLITFCLK_PRE;
    RCC->CFGR4 |= (((uint32_t)0x07) << RCC_RCC_CFGR4_FLITFCLK_PRE_Pos);

    /* Wait till HSI is ready and if Time out is reached exit */
    do {
        HSIStatus = RCC->CR & RCC_CR_HSIRDY;
        StartUpCounter++;
    } while ((HSIStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));

    if ((RCC->CR & RCC_CR_HSIRDY) != RESET) {
        HSIStatus = (uint32_t)0x01;
    }
    else {
        HSIStatus = (uint32_t)0x00;
    }

    if (HSIStatus == (uint32_t)0x01) {
        /* Flash wait state */
        ACRreg = FLASH->ACR;
        ACRreg &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
        FLASH->ACR = (uint32_t)(FLASH_Latency_2 | ACRreg);


        RCCHCLKReg = RCC->CFGR;
        RCCHCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_HPRE_Msk);
        /* HCLK = SYSCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_HPRE_DIV1 | RCCHCLKReg);

        RCCPCLKReg = RCC->CFGR;
        RCCPCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_PPRE_Msk);
        /* PCLK = HCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_PPRE_DIV1 | RCCPCLKReg);

        /* Select HSI as system clock source */
        RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI;

        /* Wait till HSI is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
        }
    }
    else { /* If fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */
    }
};
#elif (SYSCLK_SOURCE == SYSCLK_SRC_LSI)
static void SetSysClockToLSI(void) {
    __IO uint32_t StartUpCounter = 0, LSIStatus = 0;

    /* Enable LSI */
    RCC->CSR |= RCC_CSR_LSION;

    /* Wait till LSI is ready and if Time out is reached exit */
    do {
        LSIStatus = RCC->CSR & RCC_CSR_LSIRDY;
        StartUpCounter++;
    } while ((LSIStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));

    if ((RCC->CSR & RCC_CSR_LSIRDY) != RESET) {
        LSIStatus = (uint32_t)0x01;
    }
    else {
        LSIStatus = (uint32_t)0x00;
    }

    if (LSIStatus == (uint32_t)0x01) {
        /* Flash wait state */
        FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
        FLASH->ACR |= (uint32_t)FLASH_Latency_0;

        /* HCLK = SYSCLK */
        RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

        /* PCLK = HCLK */
        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;

        /* Select HSI as system clock source */
        RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_LSI;

        /* Wait till LSI is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_LSI) {
        }
    }
    else { /* If fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */
    }
};
#elif (SYSCLK_SOURCE == SYSCLK_SCR_EXTCLK_IO)
static void SetSysClockToEXTCLK(void) {
    __IO uint32_t StartUpCounter = 0, EXTCLKStatus = 0;
    __IO uint32_t ACRreg = 0;
    __IO uint32_t RCCHCLKReg = 0;
    __IO uint32_t RCCPCLKReg = 0;
    // enable EXTIO PA1/PD7/PB5/PC5

    /* Configure PA1  as CLOCK input */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);


    // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
    // GPIO_InitTypeDef GPIO_InitStructure;
    // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    // GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    // GPIO_Init(GPIOD, &GPIO_InitStructure);


    // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    // GPIO_InitTypeDef GPIO_InitStructure;
    // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    // GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    // GPIO_Init(GPIOB, &GPIO_InitStructure);

    // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
    // GPIO_InitTypeDef GPIO_InitStructure;
    // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    // GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    // GPIO_Init(GPIOC, &GPIO_InitStructure);

    /*CLOCK select */
    RCC->CFGR4 &= (uint32_t) ~(RCC_RCC_CFGR4_EXTCLK_SEL);
    RCC->CFGR4 |= (uint32_t)RCC_CFGR4_EXTCLK_SEL_PA1;
    // RCC->CFGR4 |= (uint32_t)RCC_CFGR4_EXTCLK_SEL_PB5;
    // RCC->CFGR4 |= (uint32_t)RCC_CFGR4_EXTCLK_SEL_PC5;
    // RCC->CFGR4 |= (uint32_t)RCC_CFGR4_EXTCLK_SEL_PD7;
    /* Enable EXTCLK */
    RCC->CR |= RCC_CR_EXTCLKON;

    /* Wait till LSI is ready and if Time out is reached exit */
    do {
        EXTCLKStatus = RCC->CR & RCC_CR_EXTCLKRDY;
        StartUpCounter++;
    } while ((EXTCLKStatus == 0) && (StartUpCounter != STARTUP_TIMEOUT));

    if ((RCC->CR & RCC_CR_EXTCLKRDY) != RESET) {
        EXTCLKStatus = (uint32_t)0x01;
    }
    else {
        EXTCLKStatus = (uint32_t)0x00;
    }

    if (EXTCLKStatus == (uint32_t)0x01) {
        /* Flash wait state */
        ACRreg = FLASH->ACR;
        ACRreg &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

        if (SystemCoreClock <= 16000000)
            FLASH->ACR = (uint32_t)(FLASH_Latency_0 | ACRreg);
        else if (SystemCoreClock <= 32000000)
            FLASH->ACR = (uint32_t)(FLASH_Latency_1 | ACRreg);
        else
            FLASH->ACR = (uint32_t)(FLASH_Latency_2 | ACRreg);


        RCCHCLKReg = RCC->CFGR;
        RCCHCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_HPRE_Msk);
        /* HCLK = SYSCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_HPRE_DIV1 | RCCHCLKReg);

        RCCPCLKReg = RCC->CFGR;
        RCCPCLKReg &= (uint32_t)((uint32_t)~RCC_CFGR_PPRE_Msk);
        /* PCLK = HCLK */
        RCC->CFGR = (uint32_t)(RCC_CFGR_PPRE_DIV1 | RCCPCLKReg);


        /* Select EXTCLK as system clock source */
        RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_EXTCLK;

        /* Wait till EXTCLK is used as system clock source */
        while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_EXTCLK) {
        }
    }
    else { /* If fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */
    }
};

#endif


/**
 * @brief  Update SystemCoreClock variable according to Clock Register Values.
 *         The SystemCoreClock variable contains the core clock (HCLK), it can
 *         be used by the user application to setup the SysTick timer or configure
 *         other parameters.
 *
 * @note   Each time the core clock (HCLK) changes, this function must be called
 *         to update SystemCoreClock variable value. Otherwise, any configuration
 *         based on this variable will be incorrect.
 * @param  None
 * @retval None
 */
void SystemCoreClockUpdate(void) {
    uint32_t tmp = 0, presc = 0;

    /* Get SYSCLK source -------------------------------------------------------*/
    tmp = RCC->CFGR & RCC_CFGR_SWS;

    switch (tmp) {
        case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
            SystemCoreClock = HSI_VALUE;
            break;
        case RCC_CFGR_SWS_EXTCLK: /* EXTCLK used as system clock */
            SystemCoreClock = EXTCLK_VALUE;
            break;
        case RCC_CFGR_SWS_LSI: /* LSI used as system clock */
            SystemCoreClock = LSI_VALUE;
            break;

        default: /* HSI used as system clock */
            SystemCoreClock = HSI_VALUE;
            break;
    }

    /* Compute HCLK clock frequency ----------------*/
    /* Get HCLK prescaler */
    tmp = RCC->CFGR & RCC_CFGR_HPRE;
    tmp = tmp >> 4;
    presc = AHBPrescTable[tmp];
    /* HCLK clock frequency */
    SystemCoreClock = SystemCoreClock / presc;
}
